#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   文件名称 :     __init__.py
   文件功能描述 :   功能描述
   创建人 :       小钟同学
   创建时间 :          2021/12/29
-------------------------------------------------
   修改描述-2021/12/29:
-------------------------------------------------
"""
# 来自其他
# https://www.cnpython.com/pypi/threadpool-executor-shrink-able
# 传说牛逼的史上最强的python线程池-ThreadPoolExecutorShrinkAble
# 最智能的可自动实时调节线程数量的线程池。此线程池和官方concurrent.futures的线程池 是鸭子类关系，所以可以一键替换类名 或者 import as来替换类名。 对比官方线程池，有4个创新功能或改进。
#
# 1、主要是不仅能扩大，还可自动缩小(官方内置的ThreadpoolExecutor不具备此功能，此概念是什么意思和目的，可以百度java ThreadpoolExecutor的KeepAliveTime参数的介绍)，
#
# 2、非常节制的开启多线程，例如实例化一个最大100线程数目的pool，每隔2秒submit一个函数任务，而函数每次只需要1秒就能完成，实际上只需要调节增加到1个线程就可以，不需要慢慢增加到100个线程 官方的线程池不够智能，会一直增加到最大线程数目，此线程池则不会。
#
# 3、线程池任务的queue队列，修改为有界队列
#
# 4、此线程池运行函数出错时候，直接显示线程错误，官方的线程池则不会显示错误，例如函数中写1/0,任然不现实错误。
# from threadpool_executor_shrink_able import ThreadPoolExecutorShrinkAble
# 这个是智能线程池，不是官方的concurrent.futures.threadpoolexecutor
# global_threadpool_executor = ThreadPoolExecutorShrinkAble(200)
import concurrent.futures
import asyncio
from functools import wraps, partial
import inspect
import functools

# asyncio.run_coroutine_threadsafe 和 run_in_executor 是一对反义词。

# _global_threadpool_executor = concurrent.futures.ThreadPoolExecutor(max_workers=10)
_global_threadpool_executor = None


# run_in_executor 是在异步环境（被async修饰的异步函数）里面，调用同步函数，将函数放到线程池运行防止阻塞整个事件循环的其他任务。
# 这个是将 一个concurrent.futures包的future对象 转化为 asyncio包的future对象，
# asyncio包的future对象是一个asyncio包的awaitable对象，所以可以被await，concurrent.futures.Future对象不能被await。

async def threadpool_run_in_executor(func, async_loop=None, threadpool_executor=None, *args):
    # 把同步的阻塞的任务或函数的执行，转为异步可以等待的协程的任务
    # 但是本质主要作用不是把同步变成协程运行，而是让其拥有了异步await 的用法，
    # 既能不阻塞当前事件循环，又能在同步函数执行完成return结果时拿到结果接着用
    # 在异步环境（被async修饰的异步函数）里面，调用同步函数，将函数放到线程池运行防止阻塞整个事件循环的其他任务
    global _global_threadpool_executor
    loop = async_loop or asyncio.get_event_loop()
    # threadpool_executor = threadpool_executor or _global_threadpool_executor
    _global_threadpool_executor = threadpool_executor or (
        _global_threadpool_executor if _global_threadpool_executor else concurrent.futures.ThreadPoolExecutor(
            max_workers=10))
    await loop.run_in_executor(executor=threadpool_executor, func=func, *args)


async def threadpool_run_in_executor_v2(func, *args, async_loop=None, threadpool_executor=None, **kwargs):
    # 把同步的阻塞的任务或函数的执行，转为异步可以等待的协程的任务
    # 但是本质主要作用不是把同步变成协程运行，而是让其拥有了异步await 的用法，
    # 既能不阻塞当前事件循环，又能在同步函数执行完成return结果时拿到结果接着用
    # 在异步环境（被async修饰的异步函数）里面，调用同步函数，将函数放到线程池运行防止阻塞整个事件循环的其他任务
    global _global_threadpool_executor
    loop = async_loop or asyncio.get_event_loop()
    _global_threadpool_executor = threadpool_executor or (
        _global_threadpool_executor if _global_threadpool_executor else concurrent.futures.ThreadPoolExecutor(
            max_workers=10))
    pfunc = partial(func, *args, **kwargs)
    await loop.run_in_executor(executor=_global_threadpool_executor, func=pfunc)


def sync_to_async(fn):
    '''
    示例：
    @sync_to_async
    def async_sleep(s):
        time.sleep(s)
    使用：
    await async_sleep(5)
    :param fn:
    :return:
    '''

    @functools.wraps(fn)
    async def wrapper(*args, **kwargs):
        loop = asyncio.get_event_loop()
        p_func = functools.partial(fn, *args, **kwargs)
        return await loop.run_in_executor(None, p_func)

    return wrapper


def sync_to_async_executor(fn, async_loop=None, threadpool_executor=None):
    @functools.wraps(fn)
    async def wrapper(*args, **kwargs):
        p_func = functools.partial(fn, *args, **kwargs)
        global _global_threadpool_executor
        loop = async_loop or asyncio.get_event_loop()
        _global_threadpool_executor = threadpool_executor or (
            _global_threadpool_executor if _global_threadpool_executor else concurrent.futures.ThreadPoolExecutor(
                max_workers=10))
        return await loop.run_in_executor(_global_threadpool_executor, p_func)

    return wrapper


import asyncio

if __name__ == '__main__':
    async def async_sleep1():
        await asyncio.sleep(8)


    async def async_sleep2():
        await asyncio.sleep(10)


    import time


    def sync_sleep1():
        time.sleep(8)


    def sync_slee2():
        time.sleep(10)


    @sync_to_async_executor
    def block_fun(x):  # 这是自定义的第二个同步阻塞函数
        time.sleep(5)
        print(x)
        return x * 10


    tasks = []
    tasks.append(threadpool_run_in_executor_v2(block_fun, 1))
    tasks.append(threadpool_run_in_executor_v2(block_fun, 2))
    tasks.append(threadpool_run_in_executor_v2(block_fun, 3))
    tasks.append(threadpool_run_in_executor_v2(block_fun, 5))
    tasks.append(threadpool_run_in_executor_v2(block_fun, 8))
    loopy = asyncio.get_event_loop()
    loopy.run_until_complete(asyncio.gather(*tasks))
